package elka.sag.logisticsystem.service.impl;

import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import org.apache.log4j.Logger;
import org.drools.compiler.compiler.DroolsParserException;
import org.drools.compiler.compiler.PackageBuilder;
import org.drools.core.RuleBase;
import org.drools.core.RuleBaseFactory;
import org.drools.core.WorkingMemory;
import org.springframework.core.io.ClassPathResource;

import elka.sag.logisticsystem.bean.ActionStatus;
import elka.sag.logisticsystem.bean.Order;
import elka.sag.logisticsystem.bean.Order.OrderStatus;
import elka.sag.logisticsystem.service.RuleService;

public class DroolsRuleService implements RuleService {
	private static Logger LOGGER = Logger.getLogger(DroolsRuleService.class);
	
	private ConcurrentMap<String, RuleBase> ruleBaseMap = new ConcurrentHashMap<String, RuleBase>();
	
	public OrderStatus getNextStatus(Order order, ActionStatus actionStatus, String actorClass) {
		RuleResult result = new RuleResult();
		result.setNewOrderStatus(Order.OrderStatus.ERROR);
		
		RuleBase ruleBase = ruleBaseMap.get(actorClass);
		if(ruleBase != null) {
			WorkingMemory workingMemory = ruleBase.newStatefulSession();
			workingMemory.setGlobal("order", order);
			workingMemory.setGlobal("result", result);
			workingMemory.setGlobal("logger", LOGGER);
			workingMemory.insert(actionStatus);
			workingMemory.fireAllRules();
		}
		
		return result.getNewOrderStatus();
	}

	public void loadRules(String rulePath, String actorClass) {
		try {
			Reader source = new InputStreamReader(new ClassPathResource(rulePath).getInputStream());
			PackageBuilder builder = new PackageBuilder();
			builder.addPackageFromDrl( source );
			if(builder.hasErrors()) {
				LOGGER.warn(getClass().getSimpleName() + ": Blad w budowaniu regul wnioskowania");
				LOGGER.warn(getClass().getSimpleName() + ": " + builder.getErrors());
			}
			org.drools.core.rule.Package pkg = builder.getPackage();
			RuleBase ruleBase = RuleBaseFactory.newRuleBase();
			ruleBase.addPackage( pkg );
			ruleBaseMap.putIfAbsent(actorClass, ruleBase);
		} catch(IOException e) {
			LOGGER.error(getClass().getSimpleName() + "Blad odczytu pliku z regulami, rulePath: " + rulePath);
		} catch (DroolsParserException e) {
			LOGGER.error(getClass().getSimpleName() + "Blad parsowania pliku z regulami, rulePath: " + rulePath);
		}
	}
	
	public class RuleResult {
		private Order.OrderStatus newOrderStatus;

		public Order.OrderStatus getNewOrderStatus() {
			return newOrderStatus;
		}

		public void setNewOrderStatus(Order.OrderStatus newOrderStatus) {
			this.newOrderStatus = newOrderStatus;
		}
	}
}
